package cn.xxm.scene.validate.executor;

import cn.xxm.scene.validate.annotation.Validate;
import cn.xxm.scene.validate.processor.ValidateProcessor;
import cn.xxm.scene.validate.processor.ValidateProcessorFactory;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@SuppressWarnings("rawtypes")
public class ValidatorExecuterDelegate {
	private Class<?> paramType;
	private Map<FastMethod, List<ValidateProcessor>> validPropertyCache = new HashMap<FastMethod, List<ValidateProcessor>>();
	public static Map<Class<?>, FastClass> fastClassCache = new HashMap<Class<?>, FastClass>();

	public ValidatorExecuterDelegate(Class<?> paramType){
		this.paramType = paramType;
		init();
	}
	
	private void init(){
		initValidPropertyCache(paramType);
	}
	
	public FastClass getFastClass(Class<?> clazz){
		FastClass fastClass = fastClassCache.get(clazz);
		if(fastClass == null){
			fastClass = FastClass.create(clazz);
			fastClassCache.put(clazz, fastClass);
		}
		return fastClass;
	}
	
	private void initValidPropertyCache(Class<?> clazz){
		if(clazz == null){
			return;
		}
		FastClass fastClass = this.getFastClass(clazz);
		StringBuffer strBuf = new StringBuffer();
		for (Field property : clazz.getDeclaredFields()) {
			Annotation [] annotations = property.getAnnotations();
			String name = property.getName();
			strBuf.append("get");
			strBuf.append(name);
			strBuf.setCharAt(3, Character.toUpperCase(strBuf.charAt(3)));
			initValidPropertyCache(fastClass, strBuf.toString(), annotations);
			strBuf.setLength(0);
		}
		
		for (Method method : clazz.getDeclaredMethods()) {
			Annotation [] annotations = method.getAnnotations();
			if(method.getReturnType() != void.class){
				initValidPropertyCache(fastClass, method.getName(), annotations);
			}
		}
		
		Class<?> superClass = clazz.getSuperclass();
		if(superClass.getAnnotation(Validate.class) != null){
			initValidPropertyCache(superClass);
		}
	}
	
	private void initValidPropertyCache(FastClass fastClass, String getterName, Annotation [] annotations){
		if(annotations != null && annotations.length != 0){
			List<ValidateProcessor> processors = new ArrayList<ValidateProcessor>();
			for (Annotation annotation : annotations) {
				ValidateProcessor validateProcessor = ValidateProcessorFactory.getValidateProcessor(annotation);
				if(validateProcessor != null){
					processors.add(validateProcessor);
				}
			}
			if(!processors.isEmpty()){
				FastMethod getter = fastClass.getMethod(getterName, null);
				List<ValidateProcessor> processorCache = validPropertyCache.get(getter);
				if(processorCache != null){
					processorCache.addAll(processors);
				} else {
					validPropertyCache.put(getter, processors);
				}
			}
		}
	}
	
	public Class<?> getParamType() {
		return paramType;
	}

	public Map<FastMethod, List<ValidateProcessor>> getValidPropertyCache() {
		return validPropertyCache;
	}

}
